package com.ikingtech.platform.service.job.service;

import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.common.FrameworkServerFeedbackTypeEnum;
import com.ikingtech.framework.sdk.enums.job.JobStatusEnum;
import com.ikingtech.framework.sdk.enums.job.JobTypeEnum;
import com.ikingtech.framework.sdk.job.model.rpc.JobExecuteInfo;
import com.ikingtech.framework.sdk.job.scheduler.JobScheduler;
import com.ikingtech.framework.sdk.job.scheduler.ScheduledJob;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.support.server.FrameworkServerProxy;
import com.ikingtech.platform.service.job.entity.JobDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @author tie yan
 */
@Slf4j
@RequiredArgsConstructor
public class JobService {

    private final JobRepository repo;

    private final JobScheduler<JobDO> scheduler;

    /**
     * 提交反馈信息
     * @param job 调度任务
     */
    public void feedback(ScheduledJob<JobDO> job) {
        // 获取调度任务的扩展信息
        JobDO entity = job.getExtension();
        // 提交反馈信息
        R<Object> result = FrameworkServerProxy.server().feedback(FrameworkServerFeedbackTypeEnum.JOB_FEEDBACK, this.createJobExecuteInfo(entity));
        if (!result.isSuccess()) {
            // 记录反馈失败日志
            log.error("job feedback failed[{}]", result.getMsg());
        }

        // 如果任务类型为重复执行
        if (JobTypeEnum.REPEATEDLY.name().equals(entity.getType())) {
            // 重新调度任务
            this.scheduler.schedule(this.createScheduledJob(entity));
        } else {
            // 设置任务状态为结束
            entity.setStatus(JobStatusEnum.END.name());
            // 更新任务信息
            this.repo.updateById(entity);
        }
    }

    /**
     * 解析执行时间
     * @param jobType 任务类型
     * @param corn cron表达式
     * @param nextTime 下次执行时间
     * @return 执行时间
     * @throws FrameworkException 框架异常
     */
    public long parseExecuteTime(String jobType, String corn, LocalDateTime nextTime) throws FrameworkException {
        if (JobTypeEnum.REPEATEDLY.name().equals(jobType)) {
            LocalDateTime date = Tools.Cron.next(corn);
            if (null == date) {
                throw new FrameworkException("invalidCronExpression");
            }
            return date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        } else {
            return nextTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        }
    }


    /**
     * 创建定时任务
     * @param entity 定时任务实体
     * @return 定时任务对象
     */
    public ScheduledJob<JobDO> createScheduledJob(JobDO entity) {
        ScheduledJob<JobDO> scheduledJob = new ScheduledJob<>();
        scheduledJob.setSerialNo(entity.getId());
        scheduledJob.setExecuteTime(this.parseExecuteTime(entity.getType(), entity.getCron(), entity.getNextTime()));
        scheduledJob.setExtension(entity);
        return scheduledJob;
    }


    /**
     * 创建JobExecuteInfo对象
     * @param entity JobDO对象
     * @return JobExecuteInfo对象
     */
    public JobExecuteInfo createJobExecuteInfo(JobDO entity) {
        JobExecuteInfo jobExecuteInfo = new JobExecuteInfo();
        // 设置序列号
        jobExecuteInfo.setSerialNo(entity.getId());
        // 设置执行器处理器
        jobExecuteInfo.setExecutorHandler(entity.getExecutorHandler());
        // 设置执行器客户端ID
        jobExecuteInfo.setExecutorClientId(entity.getExecutorClientId());
        // 设置执行参数
        jobExecuteInfo.setExecuteParam(entity.getParam());
        // 设置租户代码
        jobExecuteInfo.setTenantCode(entity.getTenantCode());
        return jobExecuteInfo;
    }

}
